﻿using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CRMField.Win8App.Common
{
    public static class ExtensionMethods
    {

        public static Task<OrganizationServiceConfiguration> CreateOrganizationConfigurationAsync(Uri url)
        {
            OrganizationServiceConfiguration svcConfig = null;
            var tcs = new TaskCompletionSource<OrganizationServiceConfiguration>();
            svcConfig = ServiceConfigurationFactory.CreateConfiguration<IOrganizationService>(url,
                (sender, args) =>
                {
                    if (args.Error != null) tcs.TrySetException(args.Error);
                    else if (args.Cancelled) tcs.TrySetCanceled();
                    else tcs.TrySetResult(svcConfig);
                }) as OrganizationServiceConfiguration;

            return tcs.Task as Task<OrganizationServiceConfiguration>;
        }

        public static Task<AuthenticationCredentials> AuthenticateAsync(
            this OrganizationServiceConfiguration orgSvcConfig, AuthenticationCredentials credentials)
        {
            var tcs = new TaskCompletionSource<AuthenticationCredentials>();
            EventHandler<AuthenticationCompletedEventArgs> handler = null;
            handler = (o, args) =>
            {
                orgSvcConfig.AuthenticationComplete -= handler;
                if (args.Error != null) tcs.TrySetException(args.Error);
                else if (args.Cancelled) tcs.TrySetCanceled();
                else tcs.TrySetResult(args.Result);
            };

            orgSvcConfig.AuthenticationComplete += handler;
            orgSvcConfig.Authenticate(credentials);
            return tcs.Task;
        }

        public static Task<Guid> CreateAsync(this OrganizationServiceProxy organizationServiceProxy, Entity entity)
        {
            var tcs = new TaskCompletionSource<Guid>();
            EventHandler<CreateCompletedEventArgs> handler = null;
            handler = (o, args) =>
            {
                organizationServiceProxy.CreateCompleted -= handler;
                if (args.Error != null) tcs.TrySetException(args.Error);
                else if (args.Cancelled) tcs.TrySetCanceled();
                else tcs.TrySetResult(args.Result);
            };
            organizationServiceProxy.CreateCompleted += handler;
            organizationServiceProxy.Create(entity);
            return tcs.Task;
        }

        public static Task<bool> UpdateAsync(this OrganizationServiceProxy organizationServiceProxy, Entity entity)
        {
            var tcs = new TaskCompletionSource<bool>();
            EventHandler<AsyncCompletedEventArgs> handler = null;
            handler = (o, args) =>
            {
                organizationServiceProxy.UpdateCompleted -= handler;
                if (args.Error != null) tcs.TrySetException(args.Error);
                else if (args.Cancelled) tcs.TrySetCanceled();
                else tcs.TrySetResult(true);
            };
            organizationServiceProxy.UpdateCompleted += handler;            
            organizationServiceProxy.Update(entity);
            return tcs.Task;
        }

        public static Task<EntityCollection> RetrieveMultipleAsync(this OrganizationServiceProxy organizationServiceProxy, QueryBase query)
        {
            var tcs = new TaskCompletionSource<EntityCollection>();
            EventHandler<RetrieveMultipleCompletedEventArgs> handler = null;
            handler = (o, args) =>
            {
                organizationServiceProxy.RetrieveMultipleCompleted -= handler;
                if (args.Error != null) tcs.TrySetException(args.Error);
                else if (args.Cancelled) tcs.TrySetCanceled();
                else tcs.TrySetResult(args.Result);
            };
            organizationServiceProxy.RetrieveMultipleCompleted += handler;
            organizationServiceProxy.RetrieveMultiple(query);
            return tcs.Task;
        }

        public static Task<ObservableCollection<T>> RetrieveMultipleAsync<T>(this OrganizationServiceProxy organizationServiceProxy, QueryBase query) where T : Entity
        {
            var tcs = new TaskCompletionSource<ObservableCollection<T>>();
            EventHandler<RetrieveMultipleCompletedEventArgs> handler = null;
            handler = (o, args) =>
            {
                organizationServiceProxy.RetrieveMultipleCompleted -= handler;
                if (args.Error != null) tcs.TrySetException(args.Error);
                else if (args.Cancelled) tcs.TrySetCanceled();
                else
                {
                    var observableCollection = new ObservableCollection<T>();
                    var entityCount = args.Result.Entities.Count;
                    for (int i = 0; i < entityCount; i++)
                    {
                        observableCollection.Add(args.Result[i].ToEntity<T>());
                    }
                    tcs.TrySetResult(observableCollection);
                }
            };
            organizationServiceProxy.RetrieveMultipleCompleted += handler;
            organizationServiceProxy.RetrieveMultiple(query);
            return tcs.Task;
        }

        public static Task<Response> ExecuteAsync<Request, Response>(this OrganizationServiceProxy organizationServiceProxy, Request request)
            where Request : OrganizationRequest
            where Response : OrganizationResponse
        {
            var tcs = new TaskCompletionSource<Response>();
            EventHandler<ExecuteCompletedEventArgs> handler = null;
            handler = (o, args) =>
            {
                organizationServiceProxy.ExecuteCompleted -= handler;
                if (args.Error != null) tcs.TrySetException(args.Error);
                else if (args.Cancelled) tcs.TrySetCanceled();
                else
                {
                    Response response = args.Result as Response;
                    tcs.TrySetResult(response);
                }
            };
            organizationServiceProxy.ExecuteCompleted += handler;
            organizationServiceProxy.ExecuteRequest(request);
            return tcs.Task;
        }
    }
}
